#ifndef ITERATORS_H
#define ITERATORS_H

#include <list>
#include <vector>
#include <set>
#include <unordered_map>

//-----------------------------------------------------------------
template <class E>
class Iterator {
public:
    virtual bool has_next() = 0;
    virtual E get_next() = 0;
    virtual ~Iterator() {}
};

//-----------------------------------------------------------------
template <class E>
class Iterator_List : public Iterator<E> {
private:
    typename std::list<E>::iterator begin;
    typename std::list<E>::iterator end;
    typename std::list<E>::iterator next;

public:
    Iterator_List(typename std::list<E>::iterator begin,
                  typename std::list<E>::iterator end)  {
        this->begin = begin;
        this->end = end;
        next = begin;
    }

    bool has_next() {
        return next != end;
    }

    E get_next()  {
        return *next++;
    }
};

//-----------------------------------------------------------------
template <class E>
class Iterator_Vector : public Iterator<E> {
private:
    typename std::vector<E>::iterator begin;
    typename std::vector<E>::iterator end;
    typename std::vector<E>::iterator next;

public:
    Iterator_Vector(typename std::vector<E>::iterator begin,
                    typename std::vector<E>::iterator end) {
        this->begin = begin;
        this->end = end;
        next = begin;
    }

    bool has_next() {
        return next != end;
    }

    E get_next() {
        return *next++;
    }
};

//-----------------------------------------------------------------
template <class E>
class Iterator_Set : public Iterator<E> {
private:
    typename std::set<E>::iterator begin;
    typename std::set<E>::iterator end;
    typename std::set<E>::iterator next;

public:
    Iterator_Set(typename std::set<E>::iterator begin,
                 typename std::set<E>::iterator end) {
        this->begin = begin;
        this->end = end;
        next = begin;
    }

    bool has_next() {
        return next != end;
    }

    E get_next() {
        return *next++;
    }
};

//-----------------------------------------------------------------
template <class E>
class Iterator_Hash : public Iterator<E> {
private:
    typename std::unordered_map<E,int>::iterator begin;
    typename std::unordered_map<E,int>::iterator end;
    typename std::unordered_map<E,int>::iterator next;

public:
    Iterator_Hash(typename std::unordered_map<E,int>::iterator begin,
                  typename std::unordered_map<E,int>::iterator end) {
        this->begin = begin;
        this->end = end;
        next = begin;
    }

    bool has_next()  {
        return next != end;
    }

    E get_next()  {
        return (next++)->first;
    }
};

#endif
